package im.composer.io;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;

public class SkippingEnhancedInputStream extends InputStream {

	private final SeekableByteChannel sbc;
	private long pos, mark;

	public static final SkippingEnhancedInputStream build(Path path) throws IOException {
		return new SkippingEnhancedInputStream(Files.newByteChannel(path));
	}

	public SkippingEnhancedInputStream(SeekableByteChannel sbc) {
		super();
		this.sbc = sbc;
	}

	@Override
	public int read() throws IOException {
		ByteBuffer buf = ByteBuffer.allocate(1);
		int a = sbc.read(buf);
		if (a < 1) {
			return -1;
		}
		pos++;
		return buf.array()[0] & 0xFF;
	}

	@Override
	public int read(byte[] b, int off, int len) throws IOException {
		ByteBuffer buf = ByteBuffer.allocate(len);
		int a = sbc.read(buf);
		if (a < 0) {
			throw new EOFException();
		}
		byte[] arr = buf.array();
		System.arraycopy(arr, 0, b, off, a);
		pos += a;
		return a;
	}

	@Override
	public synchronized long skip(long n) throws IOException {
		long old_pos = sbc.position();
		long new_pos = old_pos + n;
		if (new_pos > sbc.size()) {
			new_pos = sbc.size();
		}
		sbc.position(new_pos);
		pos = sbc.position();
		return pos - old_pos;
	}

	@Override
	public int available() throws IOException {
		return (int) (sbc.size() - pos);
	}

	@Override
	public void close() throws IOException {
		sbc.close();
	}

	@Override
	public synchronized void mark(int readlimit) {
		mark = pos;
	}

	@Override
	public synchronized void reset() throws IOException {
		sbc.position(mark);
		pos = mark;
	}

	@Override
	public boolean markSupported() {
		return true;
	}
}
